package org.zhaolei.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zhaolei.config.RabbitMQConfig;
import org.zhaolei.enums.BizCodeEnum;
import org.zhaolei.enums.ProductOrderStateEnum;
import org.zhaolei.enums.StockTaskStateEnum;
import org.zhaolei.exception.BizException;
import org.zhaolei.feign.ProductOrderFeignService;
import org.zhaolei.mapper.ProductMapper;
import org.zhaolei.mapper.ProductTaskMapper;
import org.zhaolei.model.ProductDO;
import org.zhaolei.model.ProductMessage;
import org.zhaolei.model.ProductTaskDO;
import org.zhaolei.request.LockProductRequest;
import org.zhaolei.request.OrderItemRequest;
import org.zhaolei.service.ProductService;
import org.zhaolei.util.JsonData;
import org.zhaolei.vo.ProductVO;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductTaskMapper productTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private ProductOrderFeignService productOrderFeignService;

    @Override
    public Map<String, Object> page(int page, int size) {

        Page<ProductDO> pageInfo = new Page<>(page, size);

        IPage<ProductDO> productDOIPage = productMapper.selectPage(pageInfo, null);

        Map<String, Object> pageMap = new HashMap<>(3);

        pageMap.put("total_record",productDOIPage.getTotal());
        pageMap.put("total_page",productDOIPage.getPages());
        pageMap.put("current_data",productDOIPage.getRecords().stream().map(
                this::beanProcess
        ).collect(Collectors.toList()));

        return pageMap;
    }

    @Override
    public ProductVO findDetailById(long productId) {
        ProductDO productDO = productMapper.selectById(productId);

        return beanProcess(productDO);
    }

    @Override
    public List<ProductVO> findProductsByIdBatch(List<Long> productIdList) {
//        return null;
        List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));

        List<ProductVO> productVOList = productDOList.stream().map(
                this::beanProcess
        ).collect(Collectors.toList());
        return productVOList;
    }

    /**
     * 锁定商品库存
     *
     * 1)遍历商品，锁定每个商品购买数量
     * 2)每一次锁定的时候，都要发送延迟消息
     * @param lockProductRequest
     * @return
     */
    @Override
    public JsonData lockProductStock(LockProductRequest lockProductRequest) {
        //获取订单号和商品列表
        String orderOutTradeNo = lockProductRequest.getOrderOutTradeNo();
        List<OrderItemRequest> orderItemRequestList = lockProductRequest.getOrderItemList();

        //获取全部商品的id，没有重复的，并查询出所有商品id对应的VO
        List<Long> productIdList = orderItemRequestList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());
        List<ProductVO> productVOList = this.findProductsByIdBatch(productIdList);

        //把上面的list变为map，key是productId 为什么要变成map？？这样可以根据商品的id获取其对应的VO，那我直接从DO获取是不是也可以呢？？
        Map<Long, ProductVO> productVOMap = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));

        for (OrderItemRequest item : orderItemRequestList) {
            //锁定商品记录并插入到product_task表中，该表中的每一条数据代表一个订单的一种商品，数量可能是多个
            int rows = productMapper.lockProductStock(item.getProductId(), item.getBuyNum());
            if (rows != 1) {
                throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
            } else {
                //锁定商品成功，下面插入product_task表中
                //插入商品product_task
                //item只包含商品id和购买数量，其他信息从productVO中获取，比如商品名称
                ProductVO productVO = productVOMap.get(item.getProductId());
                ProductTaskDO productTaskDO = new ProductTaskDO();
                productTaskDO.setBuyNum(item.getBuyNum());
                productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
                productTaskDO.setProductId(item.getProductId());
                productTaskDO.setProductName(productVO.getTitle());
                productTaskDO.setOutTradeNo(orderOutTradeNo);
                //插入数据表
                productTaskMapper.insert(productTaskDO);

                // 发送MQ延迟消息，介绍商品库存  TODO
                ProductMessage productMessage = new ProductMessage();
                productMessage.setOutTradeNo(orderOutTradeNo);
                //上面productTaskDO插入了，在数据库中自动生成了id
                productMessage.setTaskId(productTaskDO.getId());

                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getStockReleaseDelayRoutingKey(), productMessage);
                log.info("商品库存锁定信息延迟消息发送成功:{}",productMessage);
            }
        }
        return JsonData.buildSuccess();
    }

    /**
     * 修改product表中的锁定库存，更改product_task表中的锁定状态
     * @param productMessage
     * @return
     */
    @Override
    public boolean releaseProductStock(ProductMessage productMessage) {
        //获取商品id和数量
        //先获取工作单，检查其状态
        Long taskId = productMessage.getTaskId();
        ProductTaskDO productTaskDO = productTaskMapper.selectById(taskId);
        if (productTaskDO != null) {
            log.warn("工作单不存在，消息体为:{}", productMessage);
        }
        //taskDO是lock状态才处理
        if(productTaskDO.getLockState().equals(StockTaskStateEnum.LOCK.name())) {
            //查看订单状态
            JsonData jsonData = productOrderFeignService.queryProductOrderState(productTaskDO.getOutTradeNo());

            String state = jsonData.getData().toString();

            if (jsonData.getCode() == 0) {
                //订单是新建的或者已经支付
                if (state.equalsIgnoreCase(ProductOrderStateEnum.NEW.name())) {
                    //状态是NEW新建状态，则返回给消息队，列重新投递
                    log.warn("订单状态是NEW,返回给消息队列，重新投递:{}",productMessage);
                    return false;
                }
                //已经支付,不需要修改库存了
                if (state.equalsIgnoreCase(ProductOrderStateEnum.PAY.name())) {
                    //如果已经支付，修改task状态为finish
                    productTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    productTaskMapper.update(productTaskDO,new QueryWrapper<ProductTaskDO>().eq("id",taskId));
                    log.info("订单已经支付，修改库存锁定工作单FINISH状态:{}",productMessage);
                    return true;
                }
            }
            //订单不存在或者已经被取消
            log.warn("订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL,恢复商品库存,message:{}",productMessage);
            //设置TaskDO的状态为CANCEL，并更新到product_task表中
            productTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            productTaskMapper.update(productTaskDO,new QueryWrapper<ProductTaskDO>().eq("id",taskId));

            //修改库存
            productMapper.unlockProductStock(productTaskDO.getProductId(), productTaskDO.getBuyNum());

            return true;
        } else {
            log.warn("工作单状态不是LOCK，state={},消息体为:{}", productTaskDO.getLockState(), productMessage);
            return true;
        }
    }

    private ProductVO beanProcess(ProductDO productDO) {
        ProductVO productVO = new ProductVO();
        BeanUtils.copyProperties(productDO, productVO);
        //在商品VO里显示实时的库存
        productVO.setStock(productDO.getStock() - productDO.getLockStock());
        return productVO;
    }
}
